using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using Logic.Protocal.MessagePool;
using Message.Base;
using ServerBase.Base;
using UnityEngine;

namespace DL.Net
{
    public delegate void BaseMessageHandleEvent(BaseMessage msg);
    public delegate void NetConnectHandleEvent();
    public class NetAsyncMgr
    {
        private Socket m_ClientSocket;
        //客户端ID，用于通信验证
        public long ClientID;
        //缓存
        private byte[] m_BufferBytes = new byte[1024 * 1024];
        //缓存长度
        private int m_BufferLenght;
        //消息队列
        private Queue<BaseMessage> m_ReciveMessageQueue = new Queue<BaseMessage>();
        private int MAX_MESSAGE_FIRE = 30;
        //监听消息处理，在Update中调用
        private static Dictionary<int,BaseMessageHandleEvent> m_Listeners = new Dictionary<int, BaseMessageHandleEvent>();
        private readonly float m_HeartMessageIntervalTime = 10f;
        private float m_HeartMessageTimer = 0;
        
        public string Host = "192.168.0.1";
        public int Port = 8080;

        private int ReconnectionCount = 5;
        private int CurrentReconnectionCount = 5;
        private float ReconnectionInterval = 10;
        private float ReconnectionTimer = 0f;

        //链接成功
        public NetConnectHandleEvent ConnectSuccee;
        //链接断开
        public NetConnectHandleEvent ConnectClose;

        /// <summary>
        /// 初始化消息监听器
        /// </summary>
        public void InitLister()
        {
            foreach (int item in MessagePool.MessageIDs)
            {
                m_Listeners.Add(item, null);
            }
        }

        /// <summary>
        /// 添加消息监听
        /// </summary>
        /// <param name="messageID"></param>
        /// <param name="callback"></param>
        public static void AddNetMessageListener(int messageID, BaseMessageHandleEvent callback)
        {
            if (m_Listeners.ContainsKey(messageID))
            {
                m_Listeners[messageID] += callback;
            }
            else
            {
                Debug.LogWarning("已存在这个消息类型" + messageID);
            }
        }

        /// <summary>
        /// 移除网络消息监听
        /// </summary>
        /// <param name="messageID"></param>
        /// <param name="callback"></param>
        public static void RemoveNetMessageListener(int messageID, BaseMessageHandleEvent callback)
        {
            if (m_Listeners.ContainsKey(messageID))
            {
                m_Listeners[messageID] -= callback;
            }
            else
            {
                Debug.LogWarning("没有这个消息类型" + messageID);
            }
        }
        private bool _isConnected;
        public bool IsConnected => _isConnected;
        //每帧更新
        public void Update()
        {
            if (_isConnected)
            {
                m_HeartMessageTimer -= Time.deltaTime;
                MsgUpdate();
                if (m_HeartMessageTimer <= 0)
                {
                    SendHeartMessage();
                    m_HeartMessageTimer = m_HeartMessageIntervalTime;
                }
            }
            else 
            {
                ReconnectionTimer += Time.deltaTime;
            }
        }

        //更新消息
        public void MsgUpdate()
        {
            //初步判断，提升效率
            lock (m_ReciveMessageQueue)
            {
                if (m_ReciveMessageQueue.Count == 0) return;
            }
            //重复处理消息
            for (int i = 0; i < MAX_MESSAGE_FIRE; i++)
            {
                //获取第一条消息
                BaseMessage msgBase = null;
                lock (m_ReciveMessageQueue)
                {
                    if (m_ReciveMessageQueue.Count > 0)
                    {
                        msgBase = m_ReciveMessageQueue.Dequeue();
                    }
                }
                //分发消息
                if (msgBase != null)
                {
                    m_Listeners[msgBase.MessageID]?.Invoke(msgBase);
                }
                //没有消息了
                else break;
            }
        }

        public void Release()
        {
            if (_isConnected) Close();
        }

        /// <summary>
        /// 设置最大事件分发
        /// </summary>
        /// <param name="value"></param>
        public void SetMaxMessageFire(int value)
        {
            MAX_MESSAGE_FIRE = value;
        }

        /// <summary>
        /// 发送心跳消息
        /// </summary>
        private void SendHeartMessage()
        {
            Send(MessagePool.GetMessage(MessagePool.HeartMessage_ID));
        }

        public void Send(BaseMessage msg)
        {
            if (m_ClientSocket != null && m_ClientSocket.Connected && _isConnected)
            {
                byte[] bytes = msg.GetBytes();
                SocketAsyncEventArgs argsSend = SocketAsyncEventArgsPool.Inst.Get();
                argsSend.UserToken = msg;
                argsSend.SetBuffer(bytes, 0, bytes.Length);
                argsSend.Completed += SendCompleted;
                try
                {
                    if (!m_ClientSocket.SendAsync(argsSend))
                    {
                        // 如果操作同步完成，直接处理结果
                        SendCompleted(null, argsSend);
                    }
                }
                catch
                {
                    // 处理发送过程中可能发生的异常
                    Debug.Log("发送数据时发生异常");
                    Close();
                    // 确保在异常情况下也释放资源
                    argsSend.Completed -= SendCompleted;
                    SocketAsyncEventArgsPool.Inst.Return(argsSend);
                    
                    ConnectClose?.Invoke();
                    _isConnected = false;
                }
            }
            else
            {
                if (_isConnected)
                {
                    Close();
                }
            }
        }

        private void SendCompleted(object socket,SocketAsyncEventArgs args)
        {
            try
            {
                if (args.SocketError == SocketError.Success)
                {
                    
                }
                else
                {
                    Debug.Log($"{args.SocketError}");
                    Close();
                }
            }
            finally
            {
                // 确保在事件处理程序完成后释放资源
                args.Completed -= SendCompleted;
                MessagePool.ReturnMessage((BaseMessage)args.UserToken);
                SocketAsyncEventArgsPool.Inst.Return(args);
            }
        }

        private SocketAsyncEventArgs argsConnect;
        /// <summary>
        /// 连接服务器
        /// </summary>
        /// <param name="host"></param>
        /// <param name="port"></param>
        public void Connect(string host, int port)
        {
            if (_isConnected) return;
            IPEndPoint severiPEndPoint = new IPEndPoint(IPAddress.Parse(host), port);
            m_ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            argsConnect = SocketAsyncEventArgsPool.Inst.Get();
            argsConnect.RemoteEndPoint = severiPEndPoint;
            argsConnect.Completed += (socket, args1) =>
            {
                if (args1.SocketError == SocketError.Success)
                {
                    Debug.Log($"连接成功: {host}:{port}");
                    // SendHeartMessage();
                    //接收消息
                    SocketAsyncEventArgs argsRecive = new();
                    argsRecive.SetBuffer(m_BufferBytes, 0, m_BufferBytes.Length);
                    argsRecive.Completed += Recive;
                    m_ClientSocket.ReceiveAsync(argsRecive);
                    //执行事件
                    ConnectSuccee?.Invoke();
                    _isConnected = true;
                }
                else
                {
                    Debug.Log($"连接失败:{args1.SocketError}");
                    ConnectClose?.Invoke();
                    _isConnected = false;
                    m_ClientSocket = null;
                    SocketAsyncEventArgsPool.Inst.Return(argsConnect);
                }
            };
            m_ClientSocket.ConnectAsync(argsConnect);
        }
        
        /// <summary>
        /// 接受消息
        /// </summary>
        private void Recive(object socket, SocketAsyncEventArgs args)
        {
            if (args.SocketError == SocketError.Success)
            {
                int bytesLength = args.BytesTransferred;
                HandleReceiveMessage(bytesLength);
                //接收消息
                if (socket != null && m_ClientSocket.Connected && _isConnected)
                {
                    args.SetBuffer(m_BufferLenght, m_BufferBytes.Length);
                }
                m_ClientSocket.ReceiveAsync(args);
            }
            else
            {
                Debug.Log($"{args.SocketError}");
                if (_isConnected)
                {
                    ConnectClose?.Invoke();
                    SocketAsyncEventArgsPool.Inst.Return(args);
                    Close();
                }
            }
        }
        
        /// <summary>
        /// 处理接受消息  推进消息队列
        /// </summary>
        /// <param name="reciveLength"></param>
        private void HandleReceiveMessage(int reciveLength)
        {
            try
            {
                if (reciveLength == 0) return;

                //处理
                int massageID = -1;
                int messageBodyLength = 0;
                int currentIndex = 0;
                m_BufferLenght += reciveLength;

                while (true) //粘包
                {
                    if (m_BufferLenght >= 8)
                    {
                        //ID
                        massageID = BitConverter.ToInt32(m_BufferBytes, currentIndex);
                        currentIndex += 4;
                        //长度
                        messageBodyLength = BitConverter.ToInt32(m_BufferBytes, currentIndex) - 8;
                        currentIndex += 4;
                    }

                    if (m_BufferLenght - currentIndex >= messageBodyLength && massageID != -1)
                    {
                        //消息体 
                        var baseMassage = MessagePool.GetMessage(massageID);
                        baseMassage.WriteIn(m_BufferBytes, currentIndex, messageBodyLength);
                        
                        lock (m_ReciveMessageQueue)
                        {
                            m_ReciveMessageQueue.Enqueue(baseMassage);
                        }

                        currentIndex += messageBodyLength;
                        if (currentIndex == m_BufferLenght)
                        {
                            m_BufferLenght = 0;
                            break;
                        }
                    }
                    else //分包
                    {
                        Array.Copy(m_BufferBytes, currentIndex - 8, m_BufferBytes, 0, m_BufferLenght - currentIndex + 8);
                        m_BufferLenght = m_BufferLenght - currentIndex + 8;
                        break;
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine($"消息解析出错: {e.Message}");
            }
        }
        
        /// <summary>
        /// 关闭
        /// 主动断开会导致SocketAsyncEventArgsPool没有被回收。请注意
        /// </summary>
        private void Close(bool reConn = false)
        {
            if (m_ClientSocket != null)
            {
                _isConnected = false;
                Debug.Log("断开连接");
                m_ClientSocket.Send(MessagePool.GetQuitMessage().GetBytes());
                m_ClientSocket.Shutdown(SocketShutdown.Both);
                m_ClientSocket.Disconnect(false);
                m_ClientSocket.Close();
                m_ClientSocket = null;
                if (argsConnect != null)
                {
                    SocketAsyncEventArgsPool.Inst.Return(argsConnect);
                    argsConnect = null;
                }
            }

            ReconnectionTimer = 0;
            if (reConn)
            {
                //开始重连
                CurrentReconnectionCount = ReconnectionCount;
                ReconnectionTimer = ReconnectionInterval;
                while (CurrentReconnectionCount > 0)
                {
                    //说明重连成功了
                    if (_isConnected)
                    {
                        Debug.Log($"重连成功!");
                        break;
                    }
                    else
                    {
                        if (ReconnectionTimer >= ReconnectionInterval)
                        {
                            Debug.Log($"第{ReconnectionCount - CurrentReconnectionCount}次重连");
                            Connect(Host,Port);
                            CurrentReconnectionCount--;
                            ReconnectionTimer = 0;
                        }
                    }
                }
                if (!_isConnected)
                {
                    Debug.Log($"重连失败，不再尝试");
                }
            }
        }

        public void ReConnect() => Close(true);
    }
}
